package com.heo.server;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.heo.coder.BikeDeviceDecoder;
import com.heo.coder.BikeDeviceEncoder;
import com.heo.pub.ServerConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * Created by zhangcf 服务端程序主入口类
 */
@Component
public class NettyServerBootstrap extends Thread{
	private static Logger logger = Logger.getLogger(NettyServerBootstrap.class);
	private int mPort = ServerConfig.PORT;

	@Override
	public void run() {
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap mServerBootstrap = new ServerBootstrap();
			mServerBootstrap.group(bossGroup, workerGroup);
			//指定一个nio传输channel
			mServerBootstrap.channel(NioServerSocketChannel.class)
			//指定的端口设置socket地址
			.localAddress(new InetSocketAddress(mPort))
			.option(ChannelOption.SO_BACKLOG, 128)
			.option(ChannelOption.SO_TIMEOUT, 180)
			//通过NoDelay禁用Nagle,使消息立即发出去，不用等待到一定的数据量才发出去 
			.option(ChannelOption.TCP_NODELAY, true)
			.option(ChannelOption.SO_REUSEADDR, true) 
			.childOption(ChannelOption.SO_KEEPALIVE, true)
			//在Channel的ChannelPipeLine中加入 NettyServerHandle
			.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel sc) throws Exception {
					ChannelPipeline pipeline = sc.pipeline();  
			        /** 
			         * 这个地方的必须和服务端对应上。否则无法正常解码和编码 
			         */  
//			        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));  
			        pipeline.addLast("decoder", new BikeDeviceDecoder());  
			        pipeline.addLast("encoder", new BikeDeviceEncoder()); 
			        pipeline.addLast("ping", new IdleStateHandler(180, 0, 0,TimeUnit.SECONDS)); 
			        pipeline.addLast(new NettyServerSocketHandler());
				}
			});
			//异步的绑定服务器，sync() 一直到绑定完成
			ChannelFuture mChannelFuture = mServerBootstrap.bind().sync();
			logger.info("socket netty transparent start 监听端口 = " + mPort);
			//获得channel的closeFuture，阻塞当前线程，直到关闭操作完成
			mChannelFuture.channel().closeFuture().sync();
		} catch (InterruptedException e) 
		{
			logger.error(e);
			e.printStackTrace();
		} finally {
			try {
				//关闭EventLoopGroup 并释放资源
				bossGroup.shutdownGracefully().sync();
				workerGroup.shutdownGracefully().sync();
				logger.info("socket netty transparent server stop");
			} catch (InterruptedException e) {
				logger.error(e);
				e.printStackTrace();
			}
			
		}
	}
}
